package io.github.uicdb.et.recipe;

import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.uicdb.et.ElementalTheory;
import io.github.uicdb.et.ModElements;
import io.github.uicdb.et.capability.IElementalHandler;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.minecraft.core.HolderLookup;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;

@Getter
@RequiredArgsConstructor
public class TurnInRecipe implements Recipe<TurnInRecipeInput> {
    public static final RecipeType<TurnInRecipe> TYPE = RecipeType.simple(ResourceLocation.fromNamespaceAndPath(ElementalTheory.MODID, "turn_in_recipe"));

    final ElementRecipePart element;
    final Ingredient input;
    final TurnInRecipeHandler outPutItem;
    final int recipeTime;
    public static final MapCodec<TurnInRecipe> CODEC = RecordCodecBuilder.mapCodec(
            instance -> instance.group(
                    ElementRecipePart.CODEC.fieldOf("elements").forGetter(TurnInRecipe::getElement),
                    Ingredient.CODEC.fieldOf("item").forGetter(TurnInRecipe::getInput),
                    TurnInRecipeHandler.CODEC.fieldOf("outItem").forGetter(TurnInRecipe::getOutPutItem),
                    Codec.INT.fieldOf("recipeTime").forGetter(TurnInRecipe::getRecipeTime)
            ).apply(instance, TurnInRecipe::new)
    );
    public static final StreamCodec<RegistryFriendlyByteBuf, TurnInRecipe> STREAM_CODEC = StreamCodec.composite(
            ElementRecipePart.STREAM_CODEC,
            TurnInRecipe::getElement,
            Ingredient.CONTENTS_STREAM_CODEC,
            TurnInRecipe::getInput,
            TurnInRecipeHandler.STREAM_CODEC,
            TurnInRecipe::getOutPutItem,
            ByteBufCodecs.INT,
            TurnInRecipe::getRecipeTime,
            TurnInRecipe::new
    );

    @Override
    public boolean matches(@NotNull TurnInRecipeInput input, @NotNull Level level) {
        return matchItems(input)
                && matchElement(input.elementalHandler());
    }

    private boolean matchItems(TurnInRecipeInput recipeInput) {
        return input.test(recipeInput.getItem());
    }

    private boolean matchElement(IElementalHandler elementalHandler) {
        return elementalHandler.getElemental(ModElements.byHolder(element.element())) >= element.amount();
    }

    @Override
    public @NotNull ItemStack assemble(@NotNull TurnInRecipeInput recipeInput, HolderLookup.@NotNull Provider provider) {
        return recipeInput.getItem();
    }

    @Override
    public boolean canCraftInDimensions(int i, int i1) {
        return true;
    }

    @Override
    public @NotNull ItemStack getResultItem(HolderLookup.Provider provider) {
        return ItemStack.EMPTY;
    }

    @Override
    public @NotNull RecipeSerializer<?> getSerializer() {
        return Serializer.INSTANCE;
    }

    @Override
    public @NotNull RecipeType<?> getType() {
        return TYPE;
    }

    public static class Serializer implements RecipeSerializer<TurnInRecipe> {
        public static final TurnInRecipe.Serializer INSTANCE = new TurnInRecipe.Serializer();

        public @NotNull MapCodec<TurnInRecipe> codec() {
            return TurnInRecipe.CODEC;
        }

        public @NotNull StreamCodec<RegistryFriendlyByteBuf, TurnInRecipe> streamCodec() {
            return TurnInRecipe.STREAM_CODEC;
        }

    }
}
